'use strict';
const Service = require('egg').Service;
const path = require('path');
const fs = require('fs');
const pump = require('pump');
const mkdirp = require('mkdirp');
const TOP_LEVEL_RETAIN = 'TOP_LEVEL_RETAIN'; // 自定义顶级分类CODE
const mongoose = require('mongoose');
class FileService extends Service {
  /**
   * 文件上传、更新
   */
  async saveFileHandle() {
    const { ctx } = this;
    try {
      // 新增模板时查询当前分类下是否存在同名模板
      if (!ctx.request.query._id) {
        const resultList = await ctx.model.File.find({
          classify: ctx.request.query.classifyId,
          templateName: ctx.request.query.templateName,
        });
        if (resultList.length) {
          ctx.helper.fail({
            ctx,
            code: 500,
            res: '当前分类下已存在相同的模板名称!',
            detailMessage: '当前分类下已存在相同的模板名称!',
          });
          return;
        }
      }

      // 根据分类ID获取需要保存的路径
      const currentClassify = await ctx.model.Classify.findById(
        ctx.request.query.classifyId
      );
      const parentClassify = await ctx.model.Classify.findById(
        currentClassify.parent
      );
      const basePath = `app/public/`;
      const folder =
        parentClassify.classifyName === TOP_LEVEL_RETAIN
          ? `${currentClassify.classifyName}`
          : `${parentClassify.classifyName}/${currentClassify.classifyName}`;
      const filePath = basePath + folder;

      // 获取多个文件提交的数据流，多文件上传专用
      const parts = ctx.multipart({ autoFields: true });
      const files = {};
      let count = 0;
      let stream;
      // 获取当前时间作为版本号
      let dateStr = ctx.helper.dateReset(new Date(), 'yyyyMMddhhmmss');
      while ((stream = await parts()) != null) {
        count = 1;
        // 判断用户是否选择上传图片
        if (!stream.filename) {
          ctx.helper.fail({ ctx, code: 422, res: '请选择上传的文件!' });
          return;
        }
        // filename 获取上传的文件名 xxx.jpg
        const filename = stream.filename.toLowerCase();
        // fieldname 获取文件表单提交的字段名称
        const fieldname = stream.fieldname;
        // 获取文件后缀
        function getFileType(name) {
          const startIndex = name.lastIndexOf('.');
          if (startIndex !== -1) {
            return name.slice(startIndex + 1).toLowerCase();
          } else {
            return '';
          }
        }
        // 重命名文件(时间+新名称+后缀)
        const newFileName = `${dateStr}-${
          ctx.request.query.templateName
        }.${getFileType(filename)}`;
        // 拼接上传路径
        const target = path.join(filePath, path.basename(newFileName));
        // 创建可写流
        const writeStream = fs.createWriteStream(target);
        // 读取文件 && 写入 && 销毁当前流
        await pump(stream, writeStream);
        files[fieldname] = target.slice(3).replace(/\\/g, '/'); // ctx.origin
      }
      if (!count) {
        ctx.helper.success({
          ctx,
          code: 422,
          res: '请选择上传的文件!',
        });
        return;
      }
      const params = JSON.parse(JSON.stringify(ctx.request.query));
      params.createdTime = ctx.helper.dateReset(
        new Date(),
        'yyyy-MM-dd hh:mm:ss'
      );
      params.lastUpdateTime = ctx.helper.dateReset(
        new Date(),
        'yyyy-MM-dd hh:mm:ss'
      );
      //   params.templateUrl = files.templateFile;
      //   params.dataUrl = files.jsonFile;
      params.classify = params.classifyId;
      const item = params;
      console.log(123, item);
      item.isNewest = true;
      item.version = dateStr;
      // 更新上传
      if (params._id) {
        // await ctx.model.File.findByIdAndUpdate(
        //   {
        //     _id: params._id,
        //   },
        //   {
        //     $inc: { 'fileList.$[].isNewest': false },
        //   },
        //   { multi: true }
        // );
        await ctx.model.File.findOneAndUpdate(
          { _id: params._id, 'fileList.isNewest': true },
          { $set: { 'fileList.$.isNewest': false } }
        );
        // 向最前面插入一条
        await ctx.model.File.findByIdAndUpdate(params._id, {
          $push: {
            fileList: { $each: [item], $position: 0 },
          },
        });
        ctx.helper.success({
          ctx,
          code: 200,
          res: {},
        });
        return;
      }
      // 第一次上传
      params.fileList = new Array(item);
      await ctx.model.File.create(params); // 先创建一条列表数据
      ctx.helper.success({
        ctx,
        code: 200,
        res: {},
      });
    } catch (error) {
      console.log(123, error);
      ctx.logger.error(error);
      ctx.helper.fail({
        ctx,
        code: 500,
        res: '后端接口异常！',
        detailMessage: error,
      });
    }
  }
  /**
   * 文件恢复版本（指定最新版本）
   */
  async switchVersion() {
    const { ctx } = this;
    try {
      const { _id, versionNo } = ctx.request.body;
      await ctx.model.File.findOneAndUpdate(
        { _id, 'fileList.isNewest': true },
        { $set: { 'fileList.$.isNewest': false } }
      );
      await ctx.model.File.findOneAndUpdate(
        { _id, 'fileList.version': versionNo },
        { $set: { 'fileList.$.isNewest': true } }
      );
      // 数组排序
      await ctx.model.File.findByIdAndUpdate(_id, {
        $push: {
          fileList: { $each: [], $sort: { isNewest: -1, createdTime: -1 } },
        },
      });
      ctx.helper.success({
        ctx,
        code: 200,
        res: {},
      });
    } catch (error) {
      console.log(123, error);
      ctx.logger.error(error);
      ctx.helper.fail({
        ctx,
        code: 500,
        res: '后端接口异常！',
        detailMessage: error,
      });
    }
  }
  /**
   * 文件上传
   */
  async uploadFile() {
    const { ctx } = this;
    try {
      const currentClassify = await ctx.model.Classify.findById(
        ctx.request.query.classifyId
      );
      const parentClassify = await ctx.model.Classify.findById(
        currentClassify.parent
      );
      const basePath = `app/public/`;
      const folder =
        parentClassify.classifyName === TOP_LEVEL_RETAIN
          ? `${currentClassify.classifyName}`
          : `${parentClassify.classifyName}/${currentClassify.classifyName}`;
      const filePath = basePath + folder;
      // 若不存在目录就创建(多级递归创建)
      let pathtmp = basePath;
      folder.split('/').forEach(async (item) => {
        pathtmp += `${item}/`;
        await fs.mkdirSync(path.join(pathtmp), true);
      });

      // 获取多个文件提交的数据流，多文件上传专用
      const parts = ctx.multipart({ autoFields: true });
      const files = {};
      let count = 0;
      let stream;
      while ((stream = await parts()) != null) {
        count = 1;
        // 判断用户是否选择上传图片
        if (!stream.filename) {
          ctx.helper.fail({ ctx, code: 422, res: '请选择上传的文件!' });
          return;
        }
        // filename 获取上传的文件名 xxx.jpg
        const filename = stream.filename.toLowerCase();
        // fieldname 获取文件表单提交的字段名称
        const fieldname = stream.fieldname;
        // 拼接上传路径
        const target = path.join(filePath, path.basename(filename));
        // 检查是否存在相同文件
        try {
          const exists = await fs.statSync(target);
          if (exists) {
            ctx.helper.fail({
              ctx,
              code: 500,
              res: '当前上传的目录下已存在相同文件!',
              detailMessage: '当前上传的目录下已存在相同文件!',
            });
            return;
          }
        } catch (error) {}
        // 创建可写流
        const writeStream = fs.createWriteStream(target);
        // 读取文件 && 写入 && 销毁当前流
        await pump(stream, writeStream);
        files[fieldname] = target.slice(3).replace(/\\/g, '/'); // ctx.origin
      }
      if (!count) {
        ctx.helper.success({
          ctx,
          code: 422,
          res: '请选择上传的文件!',
        });
        return;
      }
      ctx.helper.success({
        ctx,
        code: 200,
        res: files,
      });
    } catch (err) {
      ctx.logger.error(err);
      ctx.helper.fail({
        ctx,
        code: 500,
        res: '后端接口异常！',
        detailMessage: err,
      });
    }
  }
  /**
   * 文件保存表单提交
   */
  async saveFile() {
    const { ctx } = this;
    try {
      const params = JSON.parse(JSON.stringify(ctx.request.body));
      params.createdTime = ctx.helper.dateReset(
        new Date(),
        'yyyy-MM-dd hh:mm:ss'
      );
      params.lastUpdateTime = ctx.helper.dateReset(
        new Date(),
        'yyyy-MM-dd hh:mm:ss'
      );
      params.classify = params.classifyId;
      const item = params;
      item.isNewest = true;
      params.fileList = new Array(item);
      const res = await ctx.model.File.create(params); // 先创建一条列表数据
      ctx.helper.success({
        ctx,
        code: 200,
        res,
      });
    } catch (err) {
      ctx.logger.error(err);
      ctx.helper.fail({
        ctx,
        code: 500,
        res: '后端接口异常！',
        detailMessage: err,
      });
    }
  }
  /**
   * 模板查询
   */
  async findFilePage() {
    const { ctx } = this;
    try {
      const { page, limit, classifyId, keyword } = ctx.request.query;
      const index = (page - 1) * limit;
      // 分页、条件查询
      const term = {};
      if (classifyId) {
        term.classify = classifyId;
      }
      if (keyword) {
        term.templateName = { $regex: keyword };
        // term.templateDescribe = { $regex: keyword };
      }
      const result = await ctx.model.File.find(term)
        .sort({})
        .skip(index)
        .limit(Number(limit));
      //   const mewResult = JSON.parse(JSON.stringify(result));
      //   mewResult.forEach((item) => {
      //     item.classifyName = item.classify.classifyName;
      //     item.classifyDescribe = item.classify.classifyDescribe;
      //     item.classify = item.classify._id;
      //     // delete item.classify;
      //   });
      const total = await ctx.model.File.find(term).countDocuments();
      ctx.helper.success({
        ctx,
        code: 200,
        res: {
          page: Number(page),
          limit: Number(limit),
          total: total,
          list: result,
        },
      });
    } catch (err) {
      ctx.logger.error(err);
      ctx.helper.fail({
        ctx,
        code: 500,
        res: '后端接口异常！',
        detailMessage: err,
      });
    }
  }
  /**
   * 模板分页查询
   */
  async findFilePages(fields) {
    const { ctx } = this;
    try {
      let {
        page,
        rows,
        sort,
        order,
        pageFlag,
        onlyCountFlag,
        filtersRaw,
        sortersRaw,
        paramsRaw,
      } = fields;
      pageFlag = Boolean(pageFlag);
      const index = (page - 1) * rows;
      // 筛选查询
      const term = {};
      filtersRaw = JSON.parse(filtersRaw);
      if (filtersRaw.length) {
        for (let index = 0; index < filtersRaw.length; index++) {
          if (filtersRaw[index].property === '_id') {
            // 验证是否为mongooseId
            const isObjId = mongoose.Types.ObjectId.isValid(
              filtersRaw[index].value
            );
            if (!isObjId) {
              ctx.helper.fail({
                ctx,
                code: 422,
                res: '查询的ID不存在！',
                detailMessage: '查询的ID不存在！',
              });
              return;
            }
          }
          term[filtersRaw[index].property] =
            filtersRaw[index].operator === '='
              ? filtersRaw[index].value
              : { $regex: filtersRaw[index].value };
        }
      }
      // 排序条件
      const sortRules = {};
      if (sort) {
        sortRules[sort] = order;
      }
      let result = [];
      let total = 0;
      console.log(1233, term);
      // 分页
      if (pageFlag) {
        result = await ctx.model.File.find(term)
          .sort(sortRules)
          .skip(index)
          .limit(Number(rows));
        console.log(22, result);
      } else {
        result = await ctx.model.File.find(term).sort(sortRules);
      }
      const newResult = JSON.parse(JSON.stringify(result));

      // 遍历获取分类全路径
      for (let index = 0; index < newResult.length; index++) {
        const currentClassify = await ctx.model.Classify.findById(
          newResult[index].classify
        ); // 当前分类
        const ancestorsClassify = await currentClassify.getAncestors({}); // 所有祖先分类
        newResult[index].classifyAllName =
          ancestorsClassify.length === 1
            ? currentClassify.classifyName
            : `${ancestorsClassify[1].classifyName}/${currentClassify.classifyName}`;
        newResult[index].classifyAllDescribe =
          ancestorsClassify.length === 1
            ? currentClassify.classifyDescribe
            : `${ancestorsClassify[1].classifyDescribe}/${currentClassify.classifyDescribe}`;
      }

      console.log(newResult);
      total = await ctx.model.File.find(term).countDocuments();
      ctx.helper.success({
        ctx,
        code: 200,
        res: {
          page: Number(page),
          rows: Number(rows),
          total: total,
          records: newResult,
        },
      });
    } catch (err) {
      ctx.logger.error(err);
      ctx.helper.fail({
        ctx,
        code: 500,
        res: '后端接口异常！',
        detailMessage: err,
      });
    }
  }
  /**
   * 获取文件
   */
  async findFileDownload() {
    const { ctx } = this;
    try {
      let { fileId, versionNo, fileType } = ctx.request.query;
      const result = await ctx.model.File.findById(fileId).populate({
        path: 'classify',
      });
      const currentPath = result.classify.classifyName;
      const parentClassify = await ctx.model.Classify.findById(
        result.classify.parent
      );
      const folder =
        parentClassify.classifyName === TOP_LEVEL_RETAIN
          ? `${currentPath}`
          : `${parentClassify.classifyName}/${currentPath}`;
      // 默认获取最新版本
      if (!versionNo) {
        // newVersionNo = await ctx.model.File.find({
        //   _id: fileId,
        //   'fileList.isNewest': true,
        // });
        const newVersionNo = await ctx.model.File.aggregate([
          { $unwind: '$fileList' },
          { $match: { 'fileList.isNewest': true } },
        ]);
        versionNo = newVersionNo[0].fileList.version;
      }
      const filePath = `app/public/${folder}/${versionNo}-${
        result.templateName
      }.${fileType || 'grf'}`;
      const data = await fs.readFileSync(filePath);
      ctx.attachment(
        `${versionNo}-${result.templateName}.${fileType || 'grf'}`
      );
      ctx.set('Content-Type', 'application/octet-stream');
      ctx.body = fs.createReadStream(filePath);
    } catch (err) {
      ctx.logger.error(err);
      ctx.helper.fail({
        ctx,
        code: 500,
        res: '后端接口异常！',
        detailMessage: err,
      });
    }
  }
  /**
   * 删除模板版本
   */
  async deleteFileHandle() {
    const { ctx } = this;
    try {
      let { _id, versionNOs } = ctx.request.body;
      // 子文档批量删除
      const result = await ctx.model.File.findByIdAndUpdate(
        _id,
        {
          $pull: {
            fileList: {
              version: { $in: versionNOs },
            },
          },
        },
        { new: true }
      );

      // 模板文件删除
      const classifyData = await ctx.model.Classify.findById(result.classify);
      const parentData = await ctx.model.Classify.findById(classifyData.parent);

      const filePath =
        parentData.classifyName !== TOP_LEVEL_RETAIN
          ? `app/public/${parentData.classifyName}/${classifyData.classifyName}/`
          : `app/public/${classifyData.classifyName}/`;
      const needDeleteFiles = versionNOs.map(
        (item) => filePath + `${item}-${result.templateName}`
      );
      for (let index = 0; index < needDeleteFiles.length; index++) {
        try {
          await fs.unlinkSync(`${needDeleteFiles[index]}.grf`);
          await fs.unlinkSync(`${needDeleteFiles[index]}.json`);
        } catch (error) {}
      }

      // 若删除了所有版本，将表头一起删除
      if (!result.fileList.length) {
        await ctx.model.File.remove({ _id });
        ctx.helper.success({
          ctx,
          code: 200,
          res: {},
        });
        return;
      }
      //  判断是否删除了最新版本，若删除了最新版本则设置最后上传的为最新版本 (过滤数组)
      const isHaveNewVersion = await ctx.model.File.findById(
        _id,
        {
          fileList: {
            $elemMatch: {
              isNewest: true,
            },
          },
        },
        {}
      );
      if (!isHaveNewVersion.fileList.length) {
        await ctx.model.File.findOneAndUpdate(
          { _id, 'fileList.version': result.fileList[0].version },
          { $set: { 'fileList.$.isNewest': true } }
        );
      }
      ctx.helper.success({
        ctx,
        code: 200,
        res: isHaveNewVersion,
      });
    } catch (err) {
      ctx.logger.error(err);
      ctx.helper.fail({
        ctx,
        code: 500,
        res: '后端接口异常！',
        detailMessage: err,
      });
    }
  }
}
module.exports = FileService;
